#include "openmove_Prefix.h"
#include "SceneBase.h"
#include "OgreEngine.h"
#include "ExampleFrameListener.h"
#include "SkeletalAnimationFrameListener.h"
#include "OgreExternalTextureSourceManager.h"
#include "OgreExternalTextureSource.h"
#include "ScenePoursuite.h"
#include "SimpleFrameListener.h"
#include "LightMaterialGenerator.h"
#include "NetBase.h"
#include "NetClient.h"

#define MOVE_DURATION 0.3f
#define DEFAULT_CAMERA_DURATION 20.0f

static Vector3 s_CameraStart(182.4f, 87.7f, 655.7f);

#define POSITIONS_SIZE 4

CScenePoursuite :: CScenePoursuite(COgreEngine &Creator, const String & Name, const int pos) : CSceneBase(Creator, Name, pos), m_pSystem(NULL), m_LastStart(0), m_CamState(NULL), m_IsCamMoving(false), m_CamMoveDuration(DEFAULT_CAMERA_DURATION)
{
	m_Positions.reserve(POSITIONS_SIZE);
}

CScenePoursuite :: ~CScenePoursuite(void)
{
}

void CScenePoursuite :: Create(TCreatorEntities const &CreatorEntities, TCreatorNodes const &CreatorNodes, TCreatorLights const &CreatorLights, ENetConfig IsClient, Vector3 &CameraStartPos)
{
	CSceneBase::Create(CreatorEntities, CreatorNodes, CreatorLights, IsClient, CameraStartPos);

#if 0
	m_GrassListener.push_back(new CSimpleFrameListener(NULL, m_OgreEngine.m_pCurrentSceneManager->getSceneNode("poursuite-foret-herbe1"), m_OgreEngine.m_pCurrentSceneManager->getEntity("poursuite-foret-herbe1")));
	m_GrassListener.push_back(new CSimpleFrameListener(NULL, m_OgreEngine.m_pCurrentSceneManager->getSceneNode("poursuite-foret-herbe2"), m_OgreEngine.m_pCurrentSceneManager->getEntity("poursuite-foret-herbe2")));

	for (TGrassListener::iterator It = m_GrassListener.begin(); It != m_GrassListener.end(); ++It)
	{
		m_FrameListeners.push_back((*It));
	}
#endif



	{
		Entity * light1Anim = findEntity(String("poursuite-foret-lumiere1"));
		if (light1Anim->hasSkeleton())
		{
			m_pLight1Bone = light1Anim->getSkeleton()->getBone(0);
		}
	}

	Entity * camTremblementAnim = findEntity(String("cam-tremblement"));
	if (camTremblementAnim->hasSkeleton())
	{
		m_pCameraTremblement = camTremblementAnim->getSkeleton()->getBone(0);
	}
	Entity * camTravAnim = findEntity(String("cam-trav"));
	if (NULL != camTravAnim && camTravAnim->hasSkeleton())
	{
		m_pCamTrav = camTravAnim->getSkeleton()->getBone(0);
	}

	Entity *ent = findEntity(String("cam-trav"));
	if (NULL != ent)
	{
		ent->getAllAnimationStates()->removeAnimationState("camera");

		if (ent->hasSkeleton() && ent->getAllAnimationStates()->hasAnimationState("camera"))
		{
			m_CamState = ent->getAnimationState("camera");
		}
	}

	//m_Timer.setTimerRate(0.075f);

	//SceneNode *node = static_cast<SceneNode *>(m_pSceneNode->getChild("poursuite-foret-herbe2"));
	//node->setScale(1, 0.6, 1);
	//node->setOrientation(Quaternion(Degree(90), Vector3::UNIT_Y));
}

static GpuProgramParametersSharedPtr fpParams;

void CScenePoursuite :: notifyMaterialSetup(uint32 pass_id, MaterialPtr &mat)
{
	CSceneBase::notifyMaterialSetup(pass_id, mat);

    if(pass_id == 0)
    {
        //fpParams = mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
    }
}

void CScenePoursuite :: notifyMaterialRender(uint32 pass_id, MaterialPtr &material)
{
	CSceneBase::notifyMaterialRender(pass_id, material);

    if(pass_id == 0)
    {
		//Real value = m_Timer.getMilliseconds() / 10000.0f;
		//value = value - Math::Floor(value);

		//fpParams->setNamedConstant("color", Vector3(0, 0, 0));

		//fpParams->setNamedConstant("useColor", value);
	}
}

static Vector3 tmpCamPos;
static Quaternion tmpCamOri;

bool CScenePoursuite :: frameStarted(const FrameEvent& evt)
{
#if 0
	if (NULL != m_pLight1Bone)
	{
		Light * light1 = findLight(String("poursuite-pointLight2"));
		if (NULL != light1)
		{
			light1->setPosition(m_pLight1Bone->getPosition());

			if (m_ShowEntitiesBBox)
			{
				Node *debuglight = m_pSceneNode->getChild("poursuite-pointLight2");
				debuglight->setPosition(light1->getPosition());
			}
		}
	}

	if (m_Timer.getMilliseconds() < 1000.0f * 60)
	{
		Real value = m_Timer.getMilliseconds() / (1000.0f * 60);
		value = value / 3.0f;
		m_OgreEngine.m_pCurrentSceneManager->setAmbientLight(ColourValue(value, value, value));
	}
#endif
	m_TimeToIdle -= evt.timeSinceLastFrame;

	for (CSceneBase::TFrustums::iterator It = m_Frustums.begin(); It != m_Frustums.end(); ++It)
	{
		(*It)->setFOVy(m_resetParams.m_FOVy);
	}

	//m_pCurrentCamera->setPosition(m_Positions.back());

	tmpCamPos = m_pCurrentCamera->getPosition();
	tmpCamOri = m_pCurrentCamera->getOrientation();

	CSceneBase::frameStarted(evt);

	if (0)
	{
		if (NULL != m_pCameraTremblement && m_pCameraFrameListener->getMoveCamera() == false)
		{
			m_pCurrentCamera->setOrientation(m_pCameraTremblement->getOrientation());
			m_OgreEngine.setDebugText("toPos: " + StringConverter::toString(m_Positions.back()));
			m_OgreEngine.setDebugText("camera: " + StringConverter::toString(m_pCurrentCamera->getOrientation()));
		}
	}

	if (NULL != m_CamState)
	{
		if (false == m_IsCamMoving)
		{
			m_CamState->setTimePosition(m_LastStart);
			m_OgreEngine.setDebugText("\nNotMoveCamera: " + StringConverter::toString(m_CamState->getTimePosition()) + "\n");
		}
		else
		{
			m_OgreEngine.setDebugText("\nMoveCamera: " + StringConverter::toString(m_CamState->getTimePosition()) + "\n");
		}
	}

	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_Z) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_PE_MoveCamera, DEFAULT_CAMERA_DURATION);
		m_pCameraFrameListener->mTimeUntilNextToggle = 1.0f;
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_X) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_PE_SetFog, 5, String("0.001"));
		m_pCameraFrameListener->mTimeUntilNextToggle = 1.0f;
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_C) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_PE_SetFog, 5, String("0.0001"));
		m_pCameraFrameListener->mTimeUntilNextToggle = 1.0f;
	} 
	if (m_pCameraFrameListener->mInputDevice->isKeyDown(KC_V) && m_pCameraFrameListener->mTimeUntilNextToggle <= 0)
	{
		fakeAddEvent(SOpenMoveDisplayPacket::e_PE_SetCamera, 0.3, String("0.0001"), Math::RangeRandom(0.5f, 2.0f), 
			Vector3(Math::RangeRandom(0.0f, 1.0f), 0, Math::RangeRandom(0.0f, 1.0f)));
		m_pCameraFrameListener->mTimeUntilNextToggle = 0.0f;
	} 

	if (0)
	{
		Entity *pLightAnim = findEntity(String("poursuite-foret-light"));
		if (NULL != pLightAnim)
		{
			AnimationState *pAnim = pLightAnim->getAllAnimationStates()->getAnimationState("lights");
			Bone * pBone = pLightAnim->getSkeleton()->getBone(0);
			Light * pPointLight = findLight(String("pointLight2"));
			if (NULL != pPointLight)
			{
				pPointLight->setDiffuseColour(pBone->getPosition().x, pBone->getPosition().y, pBone->getPosition().z);
				pPointLight->setSpecularColour(pBone->getPosition().x, pBone->getPosition().y, pBone->getPosition().z);
				m_OgreEngine.m_pCurrentSceneManager->setAmbientLight(ColourValue(pBone->getPosition().x, pBone->getPosition().y, pBone->getPosition().z));
			}
		}
	}

	// set fog
	if (1)
	{
		Real maxFog = 0.0012;
		Real minFog = 0.0005;
		Real maxCam = 0;
		Real minCam = 1000;
		Real density = ((m_pCurrentCamera->getPosition().z - minCam) * (1.0f / (maxCam - minCam)));
		density *= (maxFog - minFog);
		m_OgreEngine.m_pCurrentSceneManager->setFog(FOG_EXP, ColourValue::White, density, 0, 0.5);
	}

	return (true);
}

static Real lastH = 0.0f;
static Real lastV = 0.0f;
static Vector3 lastPos = s_CameraStart;
static Vector3 toPos = s_CameraStart;
void CScenePoursuite :: processEvents(void)
{
	CSceneBase::processEvents();

	m_IsCamMoving = false;
	bool found = false;

	for (TEvents::iterator It = m_Events.begin(); It != m_Events.end(); ++It)
	{
		switch (It->m_Packet.eventid)
		{
			case SOpenMoveDisplayPacket::e_PE_MoveCamera:
			{
				if (NULL != m_CamState && 0)
				{
					m_CamMoveDuration = It->m_Packet.duree;
					if (It->isOver())
					{
						m_IsCamMoving = false;
						m_LastStart += It->m_Packet.duree;
					}
					else
					{
						m_IsCamMoving = true;
						m_CamState->setTimePosition(m_LastStart + It->m_pTimer->getMilliseconds() / 1000.0f);
					}
				}
				break;
			}
			case SOpenMoveDisplayPacket::e_PE_SetCamera:
			{
				found = true;
				Real timer = m_Timer.getSeconds();
				if (It->m_IsFirstTime)
				{



					lastPos = tmpCamPos;
					if (m_Positions.size() > 3)
					{
						m_Positions.erase(m_Positions.begin());
					}
					if (It->m_Packet.user_position_h > 0 && It->m_Packet.user_position_v > 0)
						toPos = s_CameraStart + Vector3((It->m_Packet.user_position_h - 0.5f) * 1940.0f, 0, (It->m_Packet.user_position_v - 0.5f) * 687.1f);
					else
						toPos = m_Positions.back();

					//m_TimeToIdle = (toPos - m_pCurrentCamera->getPosition()).length();
					m_TimeToIdle = MOVE_DURATION;

					m_Positions.push_back(toPos);
				}
				Real curTime = (1.0f / It->m_Packet.duree) * It->m_pTimer->getSeconds();
				Vector3 val;
				val = Utils::linearInterpolate(lastPos, toPos, curTime);

				lastH = It->m_Packet.user_position_h;
				lastV = It->m_Packet.user_position_v;

				m_DistStep = (toPos - m_pCurrentCamera->getPosition()) / MOVE_DURATION;


				//m_pCurrentCamera->setPosition(val);
				break;
			}
			case SOpenMoveDisplayPacket::e_PE_SetFog:
			{
				Real fogDensity = StringConverter::parseReal(It->m_Packet.params);
				Real time = It->m_pTimer->getSeconds() / It->m_Packet.duree;
				Real density = m_OgreEngine.m_pCurrentSceneManager->getFogDensity();

				m_OgreEngine.m_pCurrentSceneManager->setFog(
					m_OgreEngine.m_pCurrentSceneManager->getFogMode(),
					ColourValue::White,
					density + ((fogDensity - density) * time));

				m_OgreEngine.setDebugText("time: " + StringConverter::toString(time));
			}
			default:
			{
				break;
			}
		}
	}

	m_OgreEngine.setDebugText("inter: uv: " + StringConverter::toString(lastH) + " " + StringConverter::toString(lastV));


	for (size_t i = 0; i < m_Positions.size(); ++i)
	{
		m_OgreEngine.setDebugText("pos" + StringConverter::toString(i) + ": " + StringConverter::toString(m_Positions[i]));
	}

	if (m_OgreEngine.m_pCurrentRenderWindow->getLastFPS() > 0.0f)
	{
	m_TimeToIdle = std::max(0.0f, m_TimeToIdle);
	m_TimeToIdle = std::min(MOVE_DURATION, m_TimeToIdle);
	//Vector3 val = Utils::linearInterpolate(m_pCurrentCamera->getPosition(), m_Positions.back(), 1.0f - m_TimeToIdle / MOVE_DURATION);
	Vector3 val = m_pCurrentCamera->getPosition() + m_DistStep * (MOVE_DURATION / m_OgreEngine.m_pCurrentRenderWindow->getLastFPS());
	m_pCurrentCamera->setPosition(val);
	}

	if (!found && !m_pCameraFrameListener->getMoveCamera())
	{
		//m_pCurrentCamera->setPosition(toPos);
	}	
}

void CScenePoursuite :: deleteEvents(void)
{
	//size_t nbSetCamera = 0;
	//for (TEvents::iterator It = m_Events.begin(); It != m_Events.end(); ++It)
	//{
	//	switch (It->m_Packet.eventid)
	//	{
	//		case SOpenMoveDisplayPacket::e_PE_SetCamera:
	//		{
	//			++nbSetCamera;
	//		}
	//	}
	//}

	//if (nbSetCamera == 0 && m_Positions.size() > 3)
	//{
	//	m_Positions.erase(m_Positions.begin());
	//}
	//if (1 == nbSetCamera)
	//{
	//	m_TimeToIdle = 0;
	//}
	CSceneBase::deleteEvents();
}

void CScenePoursuite :: Attach(void)
{
	CSceneBase::Attach();

	//m_pCurrentCamera->setPosition(-180.8f, 87.7f, 452.3f);
	//m_pCurrentCamera->setDirection(0, 0, -1);
	//m_OgreEngine.m_pViewPort->setBackgroundColour(ColourValue(1.0f, 1.0f, 1.0f, 1.0f));
	//m_OgreEngine.m_pCurrentSceneManager->setSkyBox(true, "SkyBox/Poursuite");
	//m_OgreEngine.m_pCurrentSceneManager->setFog(FOG_EXP, ColourValue::White, 0.0005, 0, 0.5);

	m_Positions.push_back(m_resetParams.m_camPosition);
	m_Positions.push_back(m_resetParams.m_camPosition);
	m_Positions.push_back(m_resetParams.m_camPosition);

	s_CameraStart = m_resetParams.m_camPosition;
	m_DistStep = Vector3::ZERO;
}